在 javaScript 世界中我們可以把 function 區分為
遵守 one input, one output 原則,不管輸入幾次同樣值,輸出結果永遠相同。只做運算與回傳
return
,而且不對外部世界造成任何改變 ( 沒有 Side Effect)
// -- Pure function --
const greet = (name) => {
return `Hi, I am ${name}`
}
greet('Hannah') // Hi, I'm Hannah
// -- Below all impure function --
// 沒有回傳值
const greet = (name) => {
console.log(`Hi, I am ${name}`);
}
// 有回傳值,但也有 Side Effect
let count = 0;
const greet = (name) => {
count++;
return `Count ${name} ${count}`;
}
這篇也總結前面所有 Buzz words,看似一團亂的專有名詞其實都是相關連的。
Pure Function 裡面 data 多是 immutable data 與 stateless (avoid share state) 的。另外當一個函式是 pure function 且不依賴任何外部狀態只依賴函式參數,也稱作 referential transparency (引用透明)。
要如何知道自己寫的 function 有沒有 Pure,也可以從以下三點來檢視
不管輸入什麼值 (input) 都一定會有相對應的結果 output
❌ // Not total,測試 count(5) 就 GG
const count = i => {
if(i===0) return 0;
if(i===1) return 1;
if(i===2) return 2
}
✅ // 不管輸入什麼都會有相對應的值
const count = i => {
if(i===0) return 0;
if(i===1) return 1;
if(i===2) return 2
return 100;
}
const count = i => i
❌
var x = 1;
var result = () => x++
result() // 2
result() // 3
result() // 4
✅
const result = y => y + 1;
result(1) // 2
result(1) // 2
result(1) // 2
儘管 JavaScript 世界中,們很難完全避掉但可以運用一些技巧來控管 Side Effect,讓 Side Effect 只作用在一定的範圍內,不要出現預期外的 side effect 以確保我們的程式碼能順利運行且穩定的!
❌
const add = (x, y) => {
console.log(`Adding ${x} ${y}`)
return x + y
}
✅
const add = (x, y) => {
return {result: x + y, log: `Adding ${x} ${y}`}
}
不依賴任何外部狀態只依賴函式參數
❌ // impure
var minimum = 21;
var checkAge = function(age) {
return age >= minimum;
};
✅ // pure
var checkAge = function(age) {
var minimum = 21;
return age >= minimum;
};
還有其他幾點可以檢視是不是 pure function
當我們把功能拆解成小單位的 function 再進行封裝跟組合,程式碼都可以變的很乾淨且容易理解。
let transform1 = pipe(
isString, // 是否字串
toUpper, // 全部大寫
exclaim // 最後加 !
)('hello world')
/*
> 'hello world'
|> 'hello world'
|> 'HELLO WORLD'
|> 'HELLO WORLD !'
*/
Pure Function 同輸入同輸出的特性,是可以預期的且非常穩定的,且不依賴任何外部狀態所以若要 Refactor 或 debug 也比傳統寫法容易很多。
因 Pure Function 有高預測性,所以非常容易被測試。也不需要去煩惱會受到其他 Scope 的干擾,只有輸入值才會導致改變
他不會 stuck environment,換個專案可以整包繼續用,因為不受外在環境影響 、可重覆使用性高
因為 Function 在 js 是 First Class 所以可以衍伸出各式各樣非常好用的寫法,最著名之一就是 Compose,接下來篇章也會說到這個
如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您
歡迎追蹤我的部落格,除了技術文也會分享一些在矽谷工作的甘苦。
想請教pure funcion的概念,是否類似撰寫unit testing,
透過消除對外部的依賴,只留下純粹的邏輯?
自己理解的對應關係:
函式的世界 | 測試的世界 |
---|---|
Inpure Function | Integrated Testing |
Pure Function | Unit Testing |
以我理解不太能這樣分,因為 unit test 的確通常是以 function 為單位
Integrated 是整合測試,但有可能發生 unit test 沒問題但在 Integration test 時發生錯誤
自己曾經寫過一篇文 裡面的那一張圖 "窗戶本身沒問題但整合時有問題" 可以很清楚看到這兩者之區別 XD
謝謝你的回應,我再多想想
以下為個人觀點,可能也有錯誤之處
盡信書不如無書,謝謝
單元測試與pure function是兩件不同的事情,不應該也不需要一起比較,因為它們要解決的問題是不一樣的
常常聽到的一次只測一件事情,隔離外部相依性因就是希望讓他成為最小的測試單元,如此一來當測試失敗,你會很容易知道是哪一個地方出錯
如果不管這件事情,只是將所有的外部依賴拉掉,那單元測試失敗後,能知道是哪一個地方錯誤嗎?
Pure Function 如同 Hannah 先前說的,確保相同的輸入,都有相同的輸出,就程式碼的可閱讀性來說是天然優勢,不僅好理解也好維護
所以我個人認為,pure function帶來的優點包含:可重複利用、程式碼好理解、便於維護;當然pure function更容易寫單元測試
因為我也正在看hannah的文章學習FP,所以pure function的優點還是看文章吧
單元測試的優點我覺得除了你Google搜尋到的一堆以外,那些好處你自己去google就行了,另外一個很重要的是對於你自己開發時期的信心建立,你能夠用baby step確保每一個步驟走的都是踏實的。
通常會接觸到單元測試,下一步就是TDD,講到TDD就不能不提91的30天系列,你會對於單元測試有疑慮的話,去看看吧